/*
 * GetCommand.cpp
 *
 *  Created on: Nov 16, 2009
 *      Author: kevin
 */

#include "getcommand.h"

#include <iostream>
using std::endl;
using std::cout;

#include <string>
using std::string;

#include <sstream>
using std::ostringstream;
using std::istringstream;

#include <Poco/File.h>
using Poco::File;

#include <Poco/StringTokenizer.h>
using Poco::StringTokenizer;

#include <Poco/Net/SocketAddress.h>
using Poco::Net::SocketAddress;

#include <Poco/Net/StreamSocket.h>
using Poco::Net::StreamSocket;

#include <Poco/Net/SocketStream.h>
using Poco::Net::SocketStream;

#include <Poco/Net/Socket.h>
using Poco::Net::Socket;

#include <Poco/FileStream.h>
using Poco::FileInputStream;

#include <Poco/StreamCopier.h>
using Poco::StreamCopier;

#include <Poco/Thread.h>
using Poco::Thread;

#include <Poco/DOM/DOMParser.h>
using Poco::XML::DOMParser;

#include <Poco/DOM/DOMWriter.h>
using Poco::XML::DOMWriter;

#include <Poco/DOM/Element.h>
using Poco::XML::Element;

#include <Poco/DOM/NodeList.h>
using Poco::XML::NodeList;

#include "uploadthread.h"
using Commands::UploadThread;

#include "filemanager/filemanager.h"

namespace Commands {
	const string GetCommand::NAME = "Get";

	GetCommand::GetCommand( string const& fileName, UInt16 port, SocketAddress* s):
		Command(s, true),
		fName( fileName ),
		fPort( port )
	{
		cout << "GetCommand :: Constructing GetCommand" << endl;
	}

	GetCommand::~GetCommand()
	{}

	void GetCommand::execute(){
		string host = hostname();
		cout << "host: " << host << endl;
		UInt16 port = fPort;

		cout << "GetCommand :: Setting up connection to transfer file" << endl;
		try {
			FileManager fmgr;
			File file = fmgr.searchFile(fName);

			Thread thread("getuploader");
			UploadThread uppy(host, port, file.path());
			thread.start(uppy);
			thread.join();
			
			cout << "GetCommand :: Connection closing" << endl;
			setResult("OK");
		} catch (FileNotFoundException e) {
			cout << "GetCommand :: \"" << fName << "\" is not registered!" << endl;
			setResult("NOTOK");
		}
	}

	string GetCommand::name()
	{
		return string(GetCommand::NAME);
	}

	string GetCommand::repr(){
		ostringstream out;
		DOMWriter w;
		w.writeNode(out, toXML());
		return out.str();
	}

	Document* GetCommand::toXML(Document* )
	{
		cout << "GetCommand :: Converting to xml" << endl;
		Document* doc = new Document();
		
		ostringstream port;
		port << fPort;

		//Connection stuff
		Element* conn = doc->createElement("connection");
		conn->setAttribute("port", port.str());
		doc->appendChild(conn);

		//What do we want to get
		Element* file = doc->createElement("file");
		file->setAttribute("name", fName);
		doc->appendChild(file);

		return Command::toXML(doc);
	}

	CommandCreator GetCommand::creator(){
		return GetCommand::makeCommand;
	}

	Command* GetCommand::makeCommand(string r, void* s){
		cout << "GetCommand :: MakeCommand" << endl;
		Socket* sock = (Socket*) s;
		SocketAddress address = sock->peerAddress();
		cout << "GetCommand :: Socket :: " << address.toString();
		DOMParser parser;
		Document* doc = parser.parseString(r);

		//Get the connection data
		string s_port = ((Element*)(doc->getElementsByTagName("connection")->item(0)))->getAttribute("port");
		istringstream is(s_port);
		UInt16 port; is >> port;
		cout << "GetCommand :: Port :: " << port << endl;
		//Get the filename
		string fileName = ((Element*)(doc->getElementsByTagName("file")->item(0)))->getAttribute("name");

		cout << "GetCommand :: Creating Command :: " << fileName << endl;
		cout << "GetCommand :: Port and Sock checking up :: " << port << " " << address.toString() << endl;
		return new GetCommand( fileName, port, &address );
	}
}
